package me.flyray.crm.core.blockchain.util;

import me.flyray.crm.core.blockchain.wallet.Wallet;
import me.flyray.crm.core.blockchain.wallet.WalletUtils;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * 密钥工具类
 *
 * @author sun
 * @date 2018/09/11
 */
public class KeyUtil {
    /**
     * 将BCECPublicKey 转变成string 字符串
     * @param publicKey
     * @return
     */
    public static String publicKeyToString(BCECPublicKey publicKey){
        BASE64Encoder base64Encoder = new BASE64Encoder();
        byte[] publicKeyByte = publicKey.getEncoded();
        return base64Encoder.encode(publicKeyByte);
    }
    /**
     * 从string中创建BCECPublicKey
     * @param keyString
     * @return
     * @throws NoSuchProviderException
     * @throws NoSuchAlgorithmException
     * @throws IOException
     * @throws InvalidKeySpecException
     */
    public static BCECPublicKey stringToPublicKey(String keyString) throws NoSuchProviderException, NoSuchAlgorithmException, IOException, InvalidKeySpecException {
        BASE64Decoder base64Decoder = new BASE64Decoder();
        KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", "BC");
        X509EncodedKeySpec skSpec = new X509EncodedKeySpec(base64Decoder.decodeBuffer(keyString));
        BCECPublicKey publicKey = (BCECPublicKey) keyFactory.generatePublic(skSpec);
        return publicKey;
    }

    /**
     * 将BCECPrivateKey 转变成string 字符串
     * @param privateKey
     * @return
     */
    public static String privateKeyToString(BCECPrivateKey privateKey){
        BASE64Encoder base64Encoder = new BASE64Encoder();
        byte[] privateKeyByte = privateKey.getEncoded();
        return base64Encoder.encode(privateKeyByte);
    }

    /**
     * 从string中创建BCECPrivateKey
     * @param keyString
     * @return
     * @throws NoSuchProviderException
     * @throws NoSuchAlgorithmException
     * @throws IOException
     * @throws InvalidKeySpecException
     */
    public static BCECPrivateKey stringToPrivateKey(String keyString) throws NoSuchProviderException, NoSuchAlgorithmException, IOException, InvalidKeySpecException {
        BASE64Decoder base64Decoder = new BASE64Decoder();
        KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", "BC");
        PKCS8EncodedKeySpec skSpec = new PKCS8EncodedKeySpec(base64Decoder.decodeBuffer(keyString));
        BCECPrivateKey privateKey1 = (BCECPrivateKey) keyFactory.generatePrivate(skSpec);
        return privateKey1;
    }

    /**
     * 对内容进行加密
     * @param key 加密私钥
     * @param content 内容明文
     * @return 加密之后的签名信息
     * @throws NoSuchProviderException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws SignatureException
     * @throws UnsupportedEncodingException
     */
    public static byte[] sign(BCECPrivateKey key, String content) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
        Security.addProvider(new BouncyCastleProvider());
        Signature ecdsaSign = Signature.getInstance("SHA256withECDSA", BouncyCastleProvider.PROVIDER_NAME);
        ecdsaSign.initSign(key);

        ecdsaSign.update(content.getBytes("UTF-8"));
        return ecdsaSign.sign();
    }
    /**
     * 对内容进行加密
     * @param key 加密私钥
     * @param content 内容明文
     * @return 加密之后的签名信息
     * @throws NoSuchProviderException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws SignatureException
     * @throws UnsupportedEncodingException
     */
    public static byte[] sign(BCECPrivateKey key, byte[] content) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
        Security.addProvider(new BouncyCastleProvider());
        Signature ecdsaSign = Signature.getInstance("SHA256withECDSA", BouncyCastleProvider.PROVIDER_NAME);
        ecdsaSign.initSign(key);

        ecdsaSign.update(content);
        return ecdsaSign.sign();
    }
    /**
     * 检验签名是否正确
     * @param key 公钥
     * @param sig 签名信息
     * @param content 内容明文
     * @return
     * @throws NoSuchProviderException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws SignatureException
     * @throws UnsupportedEncodingException
     */
    public static boolean verify(BCECPublicKey key, byte[] sig, String content) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
        Security.addProvider(new BouncyCastleProvider());
        Signature ecdsaVerify = Signature.getInstance("SHA256withECDSA", BouncyCastleProvider.PROVIDER_NAME);
        ecdsaVerify.initVerify(key);
        ecdsaVerify.update(content.getBytes("UTF-8"));
        return ecdsaVerify.verify(sig);
    }
    /**
     * 检验签名是否正确
     * @param key 公钥
     * @param sig 签名信息
     * @param content 内容明文
     * @return
     * @throws NoSuchProviderException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws SignatureException
     * @throws UnsupportedEncodingException
     */
    public static boolean verify(BCECPublicKey key, byte[] sig, byte[] content) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {
        Security.addProvider(new BouncyCastleProvider());
        Signature ecdsaVerify = Signature.getInstance("SHA256withECDSA", BouncyCastleProvider.PROVIDER_NAME);
        ecdsaVerify.initVerify(key);
        ecdsaVerify.update(content);
        return ecdsaVerify.verify(sig);
    }
    /**
     * 根据地址返回公钥
     * @param address 地址
     * @return 返回来的密钥可以使用stringToPublicKey恢复成密钥
     */
    public static String addressToPublicKey(String address){
    	Wallet senderWallet = WalletUtils.getInstance().getWallet(address);
        byte[] pubKey = senderWallet.getPublicKey();
        return new String(pubKey);
    }
}
